/*
 * @(#)GameAction.java $version 2011. 10. 14
 * 
 * Copyright 2011 NHN Corp. All rights Reserved.
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.hangame.mbl.action.game;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.hangame.mbl.action.SmartCommonBaseAction;
import com.hangame.mbl.constant.CommonConst;
import com.hangame.mbl.model.GameGenre;
import com.hangame.mbl.model.GameList;
import com.hangame.mbl.util.CommonUtil;
import com.hangame.mbl.util.JSONUtil;
import com.nhncorp.hancore.action.AlertForward;
import com.nhncorp.lucy.cache.CacheManager;
import com.nhncorp.lucy.security.permission.Permissions;
import com.nhncorp.lucy.web.context.WebContext;
import com.nhncorp.lucy.web.dispatcher.ActionForward;
import com.nhncorp.pagination.taglib.PaginationInfo;
import com.opensymphony.oscache.base.NeedsRefreshException;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;
import com.opensymphony.xwork.Action;

// TODO: Auto-generated Javadoc
/**
 * 게임 메인.
 * 
 * @author khpark
 */

public class GameAction extends SmartCommonBaseAction {
	
	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 6849922104540562183L;
	
	/** The log. */
	private static Log log = LogFactory.getLog(GameAction.class);

	/** The cache admin. */
	GeneralCacheAdministrator cacheAdmin = CacheManager.getCacheAdmin();

	/** The Constant KEY_CACHE_GNR_LIST. */
	private static final String KEY_CACHE_GNR_LIST = "KEY_CACHE_GNR_LIST";

	/** The game no. */
	private int gameNo;

	/* (non-Javadoc)
	 * @see com.hangame.mbl.action.SmartPortalAction#execute()
	 */
	@Override
	public String execute() throws Exception {
		return listGame();
	}

	/* (non-Javadoc)
	 * @see com.hangame.mbl.action.SmartCommonBaseAction#init()
	 */
	@Override
	public String init() throws Exception {
		String method = params.getString("m");
		boolean isReqGameNo = "detailGameInfo".equals(method) || "movieReview".equals(method) || "gameFeed".equals(method);

		if (isReqGameNo) { //gameNo가 꼭 필요한 요청인 경우
			this.gameNo = NumberUtils.toInt(params.getString("gameNo"), -1);
			if (gameNo == -1) { //gameNo 없이 요청온 경우
				return AlertForward.alertAndBack("not.exist.page");
			}
		}

		if ((StringUtils.isEmpty(method) || "listGame".equals(method)) && !"theme".equals(params.getString("reqType"))) { //게임목록 화면인경우, 화면 오른쪽에 공지 보여줌.
			setHasNotiWithoutRecoGame(true); //공지보여줌 flag set
		}

		return super.init();
	}

	/**
	 * 게임리스트.
	 * 
	 * @return the string
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public String listGame() {
		String gnr = StringUtils.defaultIfEmpty(params.getString("gnr"), ""); //장르
		int page = NumberUtils.toInt(params.getString("page"), 1);
		boolean isForTheme = "theme".equals(params.getString("reqType")); //테마 게임리스트 요청인지 여부

		List<GameList> gameList = new ArrayList<GameList>();

		PaginationInfo paginationInfo = null;

		if (isForTheme) { //테마 게임리스트 요청
			int themeId = NumberUtils.toInt(params.getString("themeId"), -1);
			if (themeId == -1) { //테마게임 리스트 요청인데, themeId 없는 경우
				return AlertForward.alertAndBack("not.exist.page");
			}

			//int gameCount = this.gameBO.getTotCntThemeGameList(themeId);
			//paginationInfo = new PaginationInfo("default", request, gameCount);
			//테마 게임목록은 페이징 사용하지않음.
			gameList = this.gameBO.getThemeGameList(themeId, 0, 100);  

			setAttribute("themeInfo", this.gameBO.getThemeByThemeId(themeId)); //테마정보. title, description
		} else { //일반 게임 리스트 요청
			ArrayList<GameGenre> gameGenreList = new ArrayList<GameGenre>();
			try {
				//TODO : 게임 장르 한글명 목록 캐싱 타임 의논 필요함
				gameGenreList = (ArrayList<GameGenre>)cacheAdmin.getFromCache(KEY_CACHE_GNR_LIST, CommonConst.EXPR_TIME_HALF_DAY);
			} catch (NeedsRefreshException nre) {
				cacheAdmin.cancelUpdate(KEY_CACHE_GNR_LIST);
				try {
					gameGenreList = this.gameBO.getGameGnrList(); //게임 장르 한글명 가져오기
					cacheAdmin.putInCache(KEY_CACHE_GNR_LIST, gameGenreList);
				} catch (Exception e) {
					gameGenreList = (ArrayList<GameGenre>)nre.getCacheContent();
					cacheAdmin.cancelUpdate(KEY_CACHE_GNR_LIST);
				}
			} catch (Exception e) {
				log.error("게임장르가져오기 에러", e); 
			}

			setAttribute("gameGenreList", gameGenreList);
			//setHasGameGnr(gameGenreList); //TODO : 현재 장르명 순서 무시하고, DB에서 가져온 순서대로 보여줌

			int gameCount = this.gameBO.getGameListCount(gnr); //게임목록 갯수
			paginationInfo = new PaginationInfo("default", request, gameCount);
			gameList = this.gameBO.getGameList(gnr, CommonUtil.calcOffset(page, paginationInfo.getPageSize()), paginationInfo.getPageSize()); //게임리스트

		}
		setAttribute("paginationInfo", paginationInfo);
		setAttribute("gameList", gameList);
		setThemeList(); //테마리스트
		setLatestNoticeList(); //공지사항 최신 3개
		return "listGame";
	}

	/**
	 * 게임 세부 기본 정보 보여주기.
	 * 
	 * @return the string
	 * @return
	 */
	public String detailGameInfo() {
		boolean result = setGameInfo(this.gameNo);
		//setRelatedGameList(gameNo);
		
		if (!result) {
			return ActionForward.alertAndGoPage("error.notuseful.url" , "/index.nhn");
		}

		return "detailGameInfo";
	}

	/**
	 * 동영상/리뷰.
	 * 
	 * @return the string
	 * @return
	 */
	public String movieReview() {
		boolean result = setGameInfo(this.gameNo);
		if (!result) {
			return ActionForward.alertAndGoPage("error.notuseful.url" , "/index.nhn");
		}
		setReviewList();

		return "movieReview";
	}

	/**
	 * 게임피드.
	 * 
	 * @return the string
	 * @return
	 */
	public String gameFeed() {
		setAttribute("sidValid", getUser().get("idvalid"));
		boolean result = setGameInfo(this.gameNo);
		if (!result) {
			return ActionForward.alertAndGoPage("error.notuseful.url" , "/index.nhn");
		}
		setFeedList();

		return "gameFeed";
	}

	/**
	 * 평점 주기.
	 * 
	 * @return the string
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	@Permissions(required = "login")
	public String saveRating() {
		int gameNo = NumberUtils.toInt(params.getString("gameNo"), -1);
		double value = NumberUtils.toDouble(params.getString("value"), -1);

		String resultMsg = WebContext.getMessage("star.rating.complete");
		boolean isSucc = true;

		try {
			if (gameNo == -1 || value == -1) { //필수 정보가 모두 넘어오지 않은 경우
				throw new Exception("파라미터 잘못 넘어옴");
			} else if (!CommonUtil.isBelongTo0Between10(value)) { //잘못된 평점이 넘어온 경우
				throw new Exception("평점이 잘못 입력되었음");
			} else { //정상인 경우
				//현재 게임에 대해 이미 평점주기 한 이력이 있는지 확인
				boolean hasRatingRecord = this.gameBO.getStarRatingLogCountById(gameNo, getUser().getUserId()) > 0;

				if (!hasRatingRecord) { //기존 이력 없는 경우
					HashMap existingGameRating = this.gameBO.getStarRating(gameNo); //기존 게임 평점 데이터
					if (existingGameRating.isEmpty()) { //insert 해야함
						this.gameBO.insertStarRating(gameNo, value, 0);
					} else { //update 해야함
						double totScore = NumberUtils.toDouble(String.valueOf(existingGameRating.get("tot_scr")), -1);
						int memberCnt = NumberUtils.toInt(String.valueOf(existingGameRating.get("prpt_mbr_cnt")), -1);
						double avgScore = 0;
						if (totScore != -1 && memberCnt != -1) { //정상인 경우
							avgScore = (totScore + value) / (memberCnt + 1);
							this.gameBO.updateStarRating(gameNo, value, avgScore);
						} else { //비정상 값
							throw new Exception("DB로 부터 잘못된 값");
						}
					}

					this.gameBO.insertStarRatingLog(getUser().getUserId(), gameNo, value); //평점 로그남김

				} else { //기존 이력 있는 경우
					resultMsg = WebContext.getMessage("star.rating.repeat");
					isSucc = false;
				}
			}
		} catch (Exception e) {
			log.error(e, e);
			resultMsg = WebContext.getMessage("star.rating.failure");
			isSucc = false;
		}

		String jsonResult = "";
		jsonResult += "{";
		jsonResult += "\"resultMsg\" : \"" + resultMsg + "\", ";
		jsonResult += "\"isSucc\" : \"" + isSucc + "\"";
		jsonResult += "}";

		setAttribute("JSON_RESULT", jsonResult);

		return "commonJsonResult";
	}

	/**
	 * 작은썸네일ID를 받아 큰썸네일 이미지URL을 ajax return 해줌.
	 * 
	 * @return the string
	 * @return
	 */
	public String showBigThumb() {
		boolean isSucc = true;
		String url = "";
		try {
			int sThumbId = NumberUtils.toInt(params.getString("sThumbId"), -1);
			if (sThumbId == -1) { //잘못된 요청인 경우
				throw new Exception("잘못된 요청");
			} else {
				url = this.gameBO.getBigScrThumbBySmallScrThumb(sThumbId);
				if (StringUtils.isEmpty(url)) { //잘못된 경우
					throw new Exception("DB데이터 가져오는중 에러");
				}
			}
		} catch (Exception e) {
			log.error(e, e);
			isSucc = false;
		}

		String jsonResult = "";
		jsonResult += "{";
		jsonResult += "\"isSucc\" : \"" + isSucc + "\"";
		jsonResult += ", \"url\" : \"" + url + "\"";
		jsonResult += "}";

		setAttribute("JSON_RESULT", jsonResult);

		return "commonJsonResult";
	}

	/**
	 * 관련 게임 목록 setAttribute.
	 * 
	 * @param gameNo the new related game list
	 */
//	private void setRelatedGameList(int gameNo) {
//		if (gameNo != -1) {
//			List<GameList> relatedGameList = this.gameBO.getRelatedGameList(gameNo);
//			setAttribute("relatedGameList", relatedGameList);
//		}
//	}

	/**
	 * 활성화된 게임메뉴인지 식별을 위한 flag를 setAttribute 해 줌.
	 * 
	 * @param gameGenreList the new checks for game gnr
	 */
//	private void setHasGameGnr(ArrayList<GameGenre> gameGenreList) {
//		String[] gnr = {"ADVENTURE", "CASUAL", "SPORT"}; //TODO 모든 게임 메뉴 set code가 들어가야 함
//
//		if (gameGenreList != null && gameGenreList.size() > 0) {
//			for (int i = 0; i < gnr.length; i++) {
//				for (int j = 0; j < gameGenreList.size(); j++) {
//					GameGenre gameGenre = (GameGenre)gameGenreList.get(j);
//					if (gnr[i].equals(gameGenre.getGameGenreCode())) {
//						setAttribute("HAS_MENU_" + gnr[i], "true");
//						break;
//					}
//				}
//			}
//		}
//	}

	/**
	 * 테마 리스트를 setAttribute함.
	 */
	private void setThemeList() {
		setAttribute("themeList", this.gameBO.getThemeList());
	}

	/**
	 * 한게임앱 오픈 여부 알아옴.
	 * 
	 * @return the string
	 * @throws IOException Signals that an I/O exception has occurred.
	 * @return
	 */
	public String isHangameAppOpen() throws IOException {
		String openType = gameBO.isHangameAppOpen();
		
		Map<String, Object> jsonMap = new HashMap<String, Object>();
		jsonMap.put("openType", openType);
		
		JSONUtil.writeJSON(response, jsonMap);
		return Action.NONE;
	}
	
	/**
	 * 평점상태.
	 * 
	 * @return the string
	 * @return
	 */
	public String isStartRating() {
		int gameNo = NumberUtils.toInt(params.getString("gameNo"), -1);
		boolean isSucc = false;
		float gameScoreRounded = 0.0f;
		int width = 0;
		try {
			if (gameNo == -1) {  //필수 정보가 모두 넘어오지 않은 경우
				throw new Exception("파라미터 잘못 넘어옴");
			}
				
			boolean hasRatingRecord = this.gameBO.getStarRatingLogCountById(gameNo, getUser().getUserId()) > 0;
			if (hasRatingRecord) {
				float gameScore = gameBO.getStarRatingLogById(gameNo, getUser().getUserId());
				width = (int)(NumberUtils.toFloat(String.valueOf(gameScore)) * 10);
				gameScoreRounded = CommonUtil.roundDecimal(gameScore, 1);
			}
			isSucc = hasRatingRecord;
		} catch (Exception e) {
			log.error(e, e);
			isSucc = false;
		}
		
		String jsonResult = "";
		jsonResult += "{";
		jsonResult += "\"isSucc\" : \"" + isSucc + "\"";
		if (isSucc) {
			jsonResult += ",\"width\" : \"" + width + "\"";
			jsonResult += ",\"gameScoreRounded\" : \"" + gameScoreRounded + "\"";
		}
		jsonResult += "}";

		setAttribute("JSON_RESULT", jsonResult);

		return "commonJsonResult";
	}
}
